home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xrubik / Rubik3d.c < prev    next >
C/C++ Source or Header  |  1996-02-05  |  39KB  |  1,158 lines

  1. /*
  2. # X-BASED RUBIK'S CUBE(tm)
  3. #
  4. #  Rubik3d.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Rubik3d */
  27.  
  28. #include <stdio.h>
  29. #include <X11/IntrinsicP.h>
  30. #include <X11/Intrinsic.h>
  31. #include <X11/StringDefs.h>
  32. #include <X11/CoreP.h>
  33. #include "RubikP.h"
  34. #include "Rubik3dP.h"
  35.  
  36. static void InitializeRubik3D();
  37. static void ExposeRubik3D();
  38. static void ResizeRubik3D();
  39. static Boolean SetValuesRubik3D();
  40. static void MoveRubik3DTl();
  41. static void MoveRubik3DTop();
  42. static void MoveRubik3DTr();
  43. static void MoveRubik3DLeft();
  44. static void MoveRubik3DRight();
  45. static void MoveRubik3DBl();
  46. static void MoveRubik3DBottom();
  47. static void MoveRubik3DBr();
  48. static void ResizePolyhedrons();
  49. static void DrawFrame();
  50. static void MapTo3D();
  51. #ifdef DEBUG
  52. static void MapFrom3D();
  53. #endif
  54. static void MapOrientFrom3D();
  55. static void CubeOffset3D();
  56.  
  57. static char defaultTranslationsRubik3D[] =
  58.   "<KeyPress>q: Quit()\n\
  59.    Ctrl<KeyPress>C: Quit()\n\
  60.    <KeyPress>KP_Divide: MoveCcw()\n\
  61.    <KeyPress>Home: MoveTl()\n\
  62.    <KeyPress>KP_7: MoveTl()\n\
  63.    <KeyPress>R7: MoveTl()\n\
  64.    <KeyPress>Up: MoveTop()\n\
  65.    <KeyPress>KP_8: MoveTop()\n\
  66.    <KeyPress>R8: MoveTop()\n\
  67.    <KeyPress>Prior: MoveTr()\n\
  68.    <KeyPress>KP_9: MoveTr()\n\
  69.    <KeyPress>R9: MoveTr()\n\
  70.    <KeyPress>Left: MoveLeft()\n\
  71.    <KeyPress>KP_4: MoveLeft()\n\
  72.    <KeyPress>R10: MoveLeft()\n\
  73.    <KeyPress>Begin: MoveCw()\n\
  74.    <KeyPress>KP_5: MoveCw()\n\
  75.    <KeyPress>R11: MoveCw()\n\
  76.    <KeyPress>Right: MoveRight()\n\
  77.    <KeyPress>KP_6: MoveRight()\n\
  78.    <KeyPress>R12: MoveRight()\n\
  79.    <KeyPress>End: MoveBl()\n\
  80.    <KeyPress>KP_1: MoveBl()\n\
  81.    <KeyPress>R13: MoveBl()\n\
  82.    <KeyPress>Down: MoveBottom()\n\
  83.    <KeyPress>KP_2: MoveBottom()\n\
  84.    <KeyPress>R14: MoveBottom()\n\
  85.    <KeyPress>Next: MoveBr()\n\
  86.    <KeyPress>KP_3: MoveBr()\n\
  87.    <KeyPress>R15: MoveBr()\n\
  88.    <Btn1Down>: Select()\n\
  89.    <Btn1Up>: Release()\n\
  90.    <KeyPress>p: Practice()\n\
  91.    <Btn2Down>(2+): Practice()\n\
  92.    <Btn2Down>: PracticeMaybe()\n\
  93.    <KeyPress>r: Randomize()\n\
  94.    <Btn3Down>(2+): Randomize()\n\
  95.    <Btn3Down>: RandomizeMaybe()\n\
  96.    <KeyPress>g: Get()\n\
  97.    <KeyPress>w: Write()\n\
  98.    <KeyPress>u: Undo()\n\
  99.    <KeyPress>s: Solve()\n\
  100.    <KeyPress>i: Increment()\n\
  101.    <KeyPress>d: Decrement()\n\
  102.    <KeyPress>o: Orientize()";
  103.  
  104. static XtActionsRec actionsListRubik3D[] =
  105. {
  106.   {"Quit", (XtActionProc) QuitRubik},
  107.   {"MoveCcw", (XtActionProc) MoveRubikCcw},
  108.   {"MoveTl", (XtActionProc) MoveRubik3DTl},
  109.   {"MoveTop", (XtActionProc) MoveRubik3DTop},
  110.   {"MoveTr", (XtActionProc) MoveRubik3DTr},
  111.   {"MoveLeft", (XtActionProc) MoveRubik3DLeft},
  112.   {"MoveCw", (XtActionProc) MoveRubikCw},
  113.   {"MoveRight", (XtActionProc) MoveRubik3DRight},
  114.   {"MoveBl", (XtActionProc) MoveRubik3DBl},
  115.   {"MoveBottom", (XtActionProc) MoveRubik3DBottom},
  116.   {"MoveBr", (XtActionProc) MoveRubik3DBr},
  117.   {"Select", (XtActionProc) SelectRubik},
  118.   {"Release", (XtActionProc) ReleaseRubik},
  119.   {"Practice", (XtActionProc) PracticeRubik},
  120.   {"PracticeMaybe", (XtActionProc) PracticeRubikMaybe},
  121.   {"Randomize", (XtActionProc) RandomizeRubik},
  122.   {"RandomizeMaybe", (XtActionProc) RandomizeRubikMaybe},
  123.   {"Get", (XtActionProc) GetRubik},
  124.   {"Write", (XtActionProc) WriteRubik},
  125.   {"Undo", (XtActionProc) UndoRubik},
  126.   {"Solve", (XtActionProc) SolveRubik},
  127.   {"Increment", (XtActionProc) IncrementRubik},
  128.   {"Decrement", (XtActionProc) DecrementRubik},
  129.   {"Orientize", (XtActionProc) OrientizeRubik}
  130. };
  131.  
  132. static XtResource resourcesRubik3D[] =
  133. {
  134.   {XtNfaceColor0, XtCLabel, XtRString, sizeof(String),
  135.    XtOffset(RubikWidget, rubik.faceName[0]), XtRString, "Red"},
  136.   {XtNfaceColor1, XtCLabel, XtRString, sizeof(String),
  137.    XtOffset(RubikWidget, rubik.faceName[1]), XtRString, "Yellow"},
  138.   {XtNfaceColor2, XtCLabel, XtRString, sizeof(String),
  139.    XtOffset(RubikWidget, rubik.faceName[2]), XtRString, "White"},
  140.   {XtNfaceColor3, XtCLabel, XtRString, sizeof(String),
  141.    XtOffset(RubikWidget, rubik.faceName[3]), XtRString, "Green"},
  142.   {XtNfaceColor4, XtCLabel, XtRString, sizeof(String),
  143.    XtOffset(RubikWidget, rubik.faceName[4]), XtRString, "Orange"},
  144.   {XtNfaceColor5, XtCLabel, XtRString, sizeof(String),
  145.    XtOffset(RubikWidget, rubik.faceName[5]), XtRString, "Blue"},
  146.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  147.    XtOffset(RubikWidget, rubik.foreground), XtRString, XtDefaultForeground},
  148.   {XtNpieceBorder, XtCColor, XtRPixel, sizeof(Pixel),
  149.    XtOffset(RubikWidget, rubik.borderColor), XtRString, XtDefaultForeground},
  150.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  151.    XtOffset(RubikWidget, core.width), XtRString, "250"},
  152.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  153.    XtOffset(RubikWidget, core.height), XtRString, "400"},
  154.   {XtNsize, XtCSize, XtRInt, sizeof(int),
  155.    XtOffset(RubikWidget, rubik.size), XtRString, "3"}, /* DEFAULTCUBES */
  156.   {XtNorient, XtCOrient, XtRBoolean, sizeof(Boolean),
  157.    XtOffset(RubikWidget, rubik.orient), XtRString, "FALSE"}, /* DEFAULTORIENT */
  158.   {XtNmono, XtCMono, XtRBoolean, sizeof(Boolean),
  159.    XtOffset(RubikWidget, rubik.mono), XtRString, "FALSE"},
  160.   {XtNface, XtCFace, XtRInt, sizeof(int),
  161.    XtOffset(RubikWidget, rubik.currentFace), XtRString, "-1"},
  162.   {XtNpos, XtCPos, XtRInt, sizeof(int),
  163.    XtOffset(RubikWidget, rubik.currentPosition), XtRString, "-1"},
  164.   {XtNdirection, XtCDirection, XtRInt, sizeof(int),
  165.    XtOffset(RubikWidget, rubik.currentDirection), XtRString, "-1"},
  166.   {XtNpractice, XtCBoolean, XtRBoolean, sizeof(Boolean),
  167.    XtOffset(RubikWidget, rubik.practice), XtRString, "FALSE"},
  168.   {XtNstart, XtCBoolean, XtRBoolean, sizeof(Boolean),
  169.    XtOffset(RubikWidget, rubik.started), XtRString, "FALSE"},
  170.   {XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  171.    XtOffset(RubikWidget, rubik.select), XtRCallback, NULL}
  172. };
  173.  
  174. Rubik3DClassRec rubik3dClassRec =
  175. {
  176.   {
  177.     (WidgetClass) &rubikClassRec,    /* superclass */
  178.     "Rubik3D",                /* class name */
  179.     sizeof(Rubik3DRec),            /* widget size */
  180.     NULL,                /* class initialize */
  181.     NULL,                /* class part initialize */
  182.     FALSE,                /* class inited */
  183.     InitializeRubik3D,            /* initialize */
  184.     NULL,                /* initialize hook */
  185.     XtInheritRealize,            /* realize */
  186.     actionsListRubik3D,            /* actions */
  187.     XtNumber(actionsListRubik3D),    /* num actions */
  188.     resourcesRubik3D,            /* resources */
  189.     XtNumber(resourcesRubik3D),        /* num resources */
  190.     NULLQUARK,                /* xrm class */
  191.     TRUE,                /* compress motion */
  192.     TRUE,                /* compress exposure */
  193.     TRUE,                /* compress enterleave */
  194.     TRUE,                /* visible interest */
  195.     NULL,                /* destroy */
  196.     ResizeRubik3D,            /* resize */
  197.     ExposeRubik3D,            /* expose */
  198.     SetValuesRubik3D,            /* set values */
  199.     NULL,                /* set values hook */
  200.     XtInheritSetValuesAlmost,        /* set values almost */
  201.     NULL,                /* get values hook */
  202.     XtInheritAcceptFocus,        /* accept focus */
  203.     XtVersion,                /* version */
  204.     NULL,                /* callback private */
  205.     defaultTranslationsRubik3D,        /* tm table */
  206.     NULL,                /* query geometry */
  207.     NULL,                /* display accelerator */
  208.     NULL                /* extension */
  209.   },
  210.   {
  211.     0                    /* ignore */
  212.   },
  213.   {
  214.     0                    /* ignore */
  215.   }
  216. };
  217.  
  218. WidgetClass rubik3dWidgetClass = (WidgetClass) &rubik3dClassRec;
  219.  
  220. static XPoint faceLoc3D[MAXFACES][MAXORIENT];
  221. static XPoint cubeLoc3D[MAXFACES][MAXORIENT + 1];
  222. static XPoint letter3DList[MAXFACES];
  223. static XPoint orient3DList[MAXFACES][MAXORIENT][2];
  224. static RowNext rotateToRow[MAXFACES] = /*CW to min face*/
  225. {
  226.   {1,   LEFT,    TOP},
  227.   {0, BOTTOM,  RIGHT},
  228.   {0,  RIGHT, BOTTOM},
  229.   {0,    TOP,   LEFT},
  230.   {1,  RIGHT, BOTTOM},
  231.   {0,   LEFT,    TOP}
  232. };
  233.  
  234. static void InitializeRubik3D(request, new)
  235.   Widget request, new;
  236. {
  237.   Rubik3DWidget w = (Rubik3DWidget) new;
  238.  
  239.   w->rubik.dim = 3;
  240.   ResizeRubik3D(w);
  241. }
  242.  
  243. static void ResizeRubik3D(w)
  244.   Rubik3DWidget w;
  245. {
  246.   XPoint tempSize;
  247.  
  248.   w->rubik.delta = 4;
  249.   w->rubik.vertical = (w->core.height >= w->core.width);
  250.   if (w->rubik.vertical) {
  251.     tempSize.y = w->core.height / MAXVIEWS;
  252.     tempSize.x = w->core.width;
  253.     if (tempSize.x >= DIVIDE(tempSize.y)) {
  254.       w->rubik3d.cubeSize.y = MAX((tempSize.y - 3 * w->rubik.delta) /
  255.         (2 * w->rubik.size) - w->rubik.delta - 2, 0);
  256.       w->rubik3d.cubeSize.x = DIVIDE(w->rubik3d.cubeSize.y);
  257.     } else {
  258.       w->rubik3d.cubeSize.x = MAX((tempSize.x - 2 * w->rubik.delta - 7) /
  259.         (2 * w->rubik.size) - w->rubik.delta, 0);
  260.       w->rubik3d.cubeSize.y = MULTIPLY(w->rubik3d.cubeSize.x);
  261.     }
  262.     w->rubik3d.cubeDiagonal = w->rubik3d.cubeSize.x / 2;
  263.     w->rubik3d.faceSize.x = w->rubik.size *
  264.       (w->rubik3d.cubeSize.x + w->rubik.delta) + w->rubik.delta + 1;
  265.     w->rubik3d.faceSize.y = w->rubik.size *
  266.       (w->rubik3d.cubeSize.y + w->rubik.delta) + w->rubik.delta + 1;
  267.     w->rubik3d.faceDiagonal = w->rubik3d.faceSize.x / 2;
  268.     w->rubik3d.viewSize.x = 2 * w->rubik3d.faceSize.x + 3;
  269.     w->rubik3d.viewSize.y = 2 * w->rubik3d.faceSize.y + 3;
  270.     w->rubik.puzzleSize.x = w->rubik3d.viewSize.x + 1;
  271.     w->rubik.puzzleSize.y = MAXVIEWS * w->rubik3d.viewSize.y + 1;
  272.   } else {
  273.     tempSize.x = w->core.width / MAXVIEWS;
  274.     tempSize.y = w->core.height;
  275.     if (tempSize.y >= DIVIDE(tempSize.x)) {
  276.       w->rubik3d.cubeSize.x = MAX((tempSize.x - 3 * w->rubik.delta) /
  277.         (2 * w->rubik.size) - w->rubik.delta - 2, 0);
  278.       w->rubik3d.cubeSize.y = DIVIDE(w->rubik3d.cubeSize.x);
  279.     } else {
  280.       w->rubik3d.cubeSize.y = MAX((tempSize.y - 2 * w->rubik.delta - 7) /
  281.         (2 * w->rubik.size) - w->rubik.delta, 0);
  282.       w->rubik3d.cubeSize.x = MULTIPLY(w->rubik3d.cubeSize.y);
  283.     }
  284.     w->rubik3d.cubeDiagonal = w->rubik3d.cubeSize.y / 2;
  285.     w->rubik3d.faceSize.y = w->rubik.size *
  286.       (w->rubik3d.cubeSize.y + w->rubik.delta) + w->rubik.delta + 1;
  287.     w->rubik3d.faceSize.x = w->rubik.size *
  288.       (w->rubik3d.cubeSize.x + w->rubik.delta) + w->rubik.delta + 1;
  289.     w->rubik3d.faceDiagonal = w->rubik3d.faceSize.y / 2;
  290.     w->rubik3d.viewSize.y = 2 * w->rubik3d.faceSize.y + 3;
  291.     w->rubik3d.viewSize.x = 2 * w->rubik3d.faceSize.x + 3;
  292.     w->rubik.puzzleSize.y = w->rubik3d.viewSize.y + 1;
  293.     w->rubik.puzzleSize.x = MAXVIEWS * w->rubik3d.viewSize.x + 1;
  294.   }
  295.   w->rubik.puzzleOffset.x = ((int) w->core.width - w->rubik.puzzleSize.x) / 2;
  296.   w->rubik.puzzleOffset.y = ((int) w->core.height - w->rubik.puzzleSize.y) /
  297.     2;
  298.   ResizePolyhedrons(w);
  299. }
  300.  
  301. static void ExposeRubik3D(new, event, region)
  302.   Widget new;
  303.   XEvent *event;
  304.   Region region; /* Not used */
  305. {
  306.   Rubik3DWidget w = (Rubik3DWidget) new;
  307.  
  308.   if (w->core.visible) {
  309.     DrawFrame(w, w->rubik.puzzleGC);
  310.     DrawAllPolyhedrons((RubikWidget) w);
  311.   }
  312. }
  313.  
  314. static Boolean SetValuesRubik3D(current, request, new)
  315.   Widget current, request, new;
  316. {
  317.   Rubik3DWidget c = (Rubik3DWidget) current, w = (Rubik3DWidget) new;
  318.   Boolean redraw = FALSE;
  319.  
  320.   if (w->rubik.size != c->rubik.size) {
  321.     ResetPolyhedrons((RubikWidget) w);
  322.     ResizeRubik3D(w);
  323.     redraw = TRUE;
  324.   }
  325.   if (w->rubik3d.cubeSize.x != c->rubik3d.cubeSize.x) {
  326.     ResizeRubik3D(w);
  327.     redraw = TRUE;
  328.   }
  329.   return (redraw);
  330. }
  331.  
  332. static void MoveRubik3DTl(w, event, args, nArgs)
  333.   Rubik3DWidget w;
  334.   XEvent *event;
  335.   char *args[];
  336.   int nArgs;
  337. {
  338.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TL,
  339.     (int) (event->xkey.state & ControlMask));
  340. }
  341.  
  342. static void MoveRubik3DTop(w, event, args, nArgs)
  343.   Rubik3DWidget w;
  344.   XEvent *event;
  345.   char *args[];
  346.   int nArgs;
  347. {
  348.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TOP,
  349.     (int) (event->xkey.state & ControlMask));
  350. }
  351.  
  352. static void MoveRubik3DTr(w, event, args, nArgs)
  353.   Rubik3DWidget w;
  354.   XEvent *event;
  355.   char *args[];
  356.   int nArgs;
  357. {
  358.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TR,
  359.     (int) (event->xkey.state & ControlMask));
  360. }
  361.  
  362. static void MoveRubik3DLeft(w, event, args, nArgs)
  363.   Rubik3DWidget w;
  364.   XEvent *event;
  365.   char *args[];
  366.   int nArgs;
  367. {
  368.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, LEFT,
  369.     (int) (event->xkey.state & ControlMask));
  370. }
  371.  
  372. static void MoveRubik3DRight(w, event, args, nArgs)
  373.   Rubik3DWidget w;
  374.   XEvent *event;
  375.   char *args[];
  376.   int nArgs;
  377. {
  378.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, RIGHT,
  379.     (int) (event->xkey.state & ControlMask));
  380. }
  381.  
  382. static void MoveRubik3DBl(w, event, args, nArgs)
  383.   Rubik3DWidget w;
  384.   XEvent *event;
  385.   char *args[];
  386.   int nArgs;
  387. {
  388.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BL,
  389.     (int) (event->xkey.state & ControlMask));
  390. }
  391.  
  392. static void MoveRubik3DBottom(w, event, args, nArgs)
  393.   Rubik3DWidget w;
  394.   XEvent *event;
  395.   char *args[];
  396.   int nArgs;
  397. {
  398.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BOTTOM,
  399.     (int) (event->xkey.state & ControlMask));
  400. }
  401.  
  402. static void MoveRubik3DBr(w, event, args, nArgs)
  403.   Rubik3DWidget w;
  404.   XEvent *event;
  405.   char *args[];
  406.   int nArgs;
  407. {
  408.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BR,
  409.     (int) (event->xkey.state & ControlMask));
  410. }
  411.  
  412. static void ResizePolyhedrons(w)
  413.   Rubik3DWidget w;
  414. {
  415.   int face, orient, side, corner;
  416.   XPoint subcubeLoc3D[MAXFACES][MAXORIENT];
  417.   XPoint diamondLoc3D[MAXFACES][MAXORIENT];
  418.   XPoint subdiamondLoc3D[MAXFACES][MAXORIENT];
  419.  
  420.   w->rubik.letterOffset.x = -2;
  421.   w->rubik.letterOffset.y = 4;
  422.   w->rubik3d.viewMiddle.x = w->rubik3d.faceSize.x +
  423.     w->rubik.puzzleOffset.x;
  424.   w->rubik3d.viewMiddle.y = w->rubik3d.faceSize.y +
  425.     w->rubik.puzzleOffset.y;
  426.   for (face = 0; face < MAXFACES; face++) {
  427.     faceLoc3D[face][0].x = w->rubik3d.viewMiddle.x;
  428.     faceLoc3D[face][0].y = w->rubik3d.viewMiddle.y;
  429.     for (orient = 1; orient < MAXORIENT; orient++) {
  430.       faceLoc3D[face][orient].x = w->rubik3d.faceSize.x;
  431.       faceLoc3D[face][orient].y = w->rubik3d.faceSize.y;
  432.     }
  433.   }
  434.   if (w->rubik.vertical) {
  435.     faceLoc3D[0][1].x /= -2;
  436.     faceLoc3D[0][1].y /= -1;
  437.     faceLoc3D[0][2].y = 0;
  438.     faceLoc3D[0][3].x /= 2;
  439.  
  440.     faceLoc3D[1][1].x /= -2;
  441.     faceLoc3D[1][2].x /= -2;
  442.     faceLoc3D[1][2].y /= -1;
  443.     faceLoc3D[1][3].x /= 2;
  444.     faceLoc3D[1][3].y /= -1;
  445.  
  446.     faceLoc3D[2][1].y = 0;
  447.     faceLoc3D[2][2].x /= -2;
  448.     faceLoc3D[2][3].x /= -1;
  449.     faceLoc3D[2][3].y = 0;
  450.  
  451.     for (face = MAXFACES / 2; face < MAXFACES; face++)
  452.       faceLoc3D[face][0].y += w->rubik3d.viewSize.y + 3;
  453.  
  454.     faceLoc3D[3][1].x /= 2;
  455.     faceLoc3D[3][1].y /= -1;
  456.     faceLoc3D[3][2].x /= 2;
  457.     faceLoc3D[3][3].x /= -2;
  458.  
  459.     faceLoc3D[4][1].x /= -1;
  460.     faceLoc3D[4][1].y = 0;
  461.     faceLoc3D[4][2].x /= 2;
  462.     faceLoc3D[4][2].y /= -1;
  463.     faceLoc3D[4][3].y = 0;
  464.  
  465.     faceLoc3D[5][1].x /= 2;
  466.     faceLoc3D[5][2].x /= -1;
  467.     faceLoc3D[5][2].y = 0;
  468.     faceLoc3D[5][3].x /= -2;
  469.     faceLoc3D[5][3].y /= -1;
  470.   } else {
  471.     faceLoc3D[0][1].x /= -1;
  472.     faceLoc3D[0][1].y /= -2;
  473.     faceLoc3D[0][2].y /= -2;
  474.     faceLoc3D[0][3].y /= 2;
  475.  
  476.     faceLoc3D[1][1].x = 0;
  477.     faceLoc3D[1][2].x /= -1;
  478.     faceLoc3D[1][2].y /= -2;
  479.     faceLoc3D[1][3].x = 0;
  480.     faceLoc3D[1][3].y /= -1;
  481.  
  482.     faceLoc3D[2][1].y /= -2;
  483.     faceLoc3D[2][2].x = 0;
  484.     faceLoc3D[2][3].y /= 2;
  485.     faceLoc3D[2][3].x /= -1;
  486.  
  487.     for (face = MAXFACES / 2; face < MAXFACES; face++)
  488.        faceLoc3D[face][0].x += w->rubik3d.viewSize.x + 3;
  489.  
  490.     faceLoc3D[3][1].x /= -1;
  491.     faceLoc3D[3][1].y /= 2;
  492.     faceLoc3D[3][2].x = 0;
  493.     faceLoc3D[3][2].y /= -1;
  494.     faceLoc3D[3][3].y /= -2;
  495.  
  496.     faceLoc3D[4][1].y /= 2;
  497.     faceLoc3D[4][2].x /= -1;
  498.     faceLoc3D[4][2].y /= 2;
  499.     faceLoc3D[4][3].x /= -1;
  500.     faceLoc3D[4][3].y /= -2;
  501.  
  502.     faceLoc3D[5][1].x = 0;
  503.     faceLoc3D[5][1].y /= -1;
  504.     faceLoc3D[5][2].y /= 2;
  505.     faceLoc3D[5][3].x = 0;
  506.   }
  507.   for (face = 0; face < MAXFACES; face++) {
  508.     cubeLoc3D[face][0].x = faceLoc3D[face][0].x;
  509.     cubeLoc3D[face][0].y = faceLoc3D[face][0].y;
  510.     subcubeLoc3D[face][0].x = faceLoc3D[face][0].x;
  511.     subcubeLoc3D[face][0].y = faceLoc3D[face][0].y;
  512.     for (orient = 1; orient < MAXORIENT; orient++) {
  513.       cubeLoc3D[face][orient].x =
  514.         (faceLoc3D[face][orient].x - (3 + w->rubik.size) *
  515.          w->rubik.delta * faceLoc3D[face][orient].x /
  516.          w->rubik3d.faceSize.x) / w->rubik.size;
  517.       cubeLoc3D[face][orient].y =
  518.         (faceLoc3D[face][orient].y - (3 + w->rubik.size) *
  519.          w->rubik.delta * faceLoc3D[face][orient].y /
  520.          w->rubik3d.faceSize.y) / w->rubik.size;
  521.       subcubeLoc3D[face][orient].x =
  522.         (faceLoc3D[face][orient].x - (5 + w->rubik.size) *
  523.          w->rubik.delta * faceLoc3D[face][orient].x /
  524.          w->rubik3d.faceSize.x) / (2 * w->rubik.size);
  525.       subcubeLoc3D[face][orient].y =
  526.         (faceLoc3D[face][orient].y - (5 + w->rubik.size) *
  527.          w->rubik.delta * faceLoc3D[face][orient].y /
  528.          w->rubik3d.faceSize.y) / (2 * w->rubik.size);
  529.     }
  530.     cubeLoc3D[face][MAXORIENT].x = -cubeLoc3D[face][1].x -
  531.       cubeLoc3D[face][2].x - cubeLoc3D[face][3].x;
  532.     cubeLoc3D[face][MAXORIENT].y = -cubeLoc3D[face][1].y -
  533.       cubeLoc3D[face][2].y - cubeLoc3D[face][3].y;
  534.   }
  535.   w->rubik3d.cubeSize.x = (w->rubik3d.faceSize.x - w->rubik.delta) /
  536.     w->rubik.size - w->rubik.delta;
  537.   w->rubik3d.cubeDiagonal = (w->rubik3d.faceDiagonal - w->rubik.delta) /
  538.     w->rubik.size - w->rubik.delta;
  539.   w->rubik3d.cubeSize.y = (w->rubik3d.faceSize.y - w->rubik.delta) /
  540.     w->rubik.size - w->rubik.delta;
  541.   w->rubik3d.cubeDiag = (w->rubik3d.faceDiagonal + w->rubik.delta) /
  542.     w->rubik.size + w->rubik.delta;
  543.   if (w->rubik.vertical) {  
  544.     letter3DList[0].x = w->rubik3d.cubeSize.x / 4;
  545.     letter3DList[0].y = -w->rubik3d.cubeSize.y / 2;
  546.     letter3DList[1].x = -w->rubik3d.cubeDiagonal;
  547.     letter3DList[1].y = 0;
  548.     letter3DList[2].x = w->rubik3d.cubeSize.x / 4;
  549.     letter3DList[2].y = w->rubik3d.cubeSize.y / 2;
  550.     letter3DList[3].x = w->rubik3d.cubeDiagonal;
  551.     letter3DList[3].y = 0;
  552.     letter3DList[4].x = -w->rubik3d.cubeSize.x / 4;
  553.     letter3DList[4].y = -w->rubik3d.cubeSize.y / 2;
  554.     letter3DList[5].x = -w->rubik3d.cubeSize.x / 4;
  555.     letter3DList[5].y = w->rubik3d.cubeSize.y / 2;
  556.   } else {
  557.     letter3DList[0].x = 0;
  558.     letter3DList[0].y = -w->rubik3d.cubeDiagonal;
  559.     letter3DList[1].x = -w->rubik3d.cubeSize.x / 2;
  560.     letter3DList[1].y = w->rubik3d.cubeSize.y / 4;
  561.     letter3DList[2].x = w->rubik3d.cubeSize.x / 2;
  562.     letter3DList[2].y = w->rubik3d.cubeSize.y / 4;
  563.     letter3DList[3].x = -w->rubik3d.cubeSize.x / 2;
  564.     letter3DList[3].y = -w->rubik3d.cubeSize.y / 4;
  565.     letter3DList[4].x = 0;
  566.     letter3DList[4].y = w->rubik3d.cubeDiagonal;
  567.     letter3DList[5].x = w->rubik3d.cubeSize.x / 2;
  568.     letter3DList[5].y = -w->rubik3d.cubeSize.y / 4;
  569.   }
  570.   /* The following figures out where to put the orient lines */
  571.   for (face = 0; face < MAXFACES; face++) {
  572.     for (orient = 0; orient < MAXORIENT - 1; orient++) {
  573.       diamondLoc3D[face][orient].x = (cubeLoc3D[face][orient].x +
  574.         cubeLoc3D[face][orient + 1].x) / 2;
  575.       diamondLoc3D[face][orient].y = (cubeLoc3D[face][orient].y +
  576.         cubeLoc3D[face][orient + 1].y) / 2;
  577.       subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][orient].x +
  578.         subcubeLoc3D[face][orient + 1].x) / 2;
  579.       subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][orient].y +
  580.         subcubeLoc3D[face][orient + 1].y) / 2;
  581.     }
  582.     /* Its a parallelagram so take advantage of that */
  583.     diamondLoc3D[face][orient].x = (cubeLoc3D[face][MAXORIENT - 1].x -
  584.       cubeLoc3D[face][MAXORIENT / 2].x) / 2;
  585.     diamondLoc3D[face][orient].y = (cubeLoc3D[face][MAXORIENT - 1].y -
  586.       cubeLoc3D[face][MAXORIENT / 2].y) / 2;
  587.     subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][MAXORIENT - 1].x -
  588.       subcubeLoc3D[face][MAXORIENT / 2].x) / 2;
  589.     subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][MAXORIENT - 1].y -
  590.       subcubeLoc3D[face][MAXORIENT / 2].y) / 2;
  591.  
  592.     MapOrientFrom3D(face, 1, &corner);
  593.     orient3DList[face][corner][0].x = cubeLoc3D[face][1].x / 2;
  594.     orient3DList[face][corner][0].y = cubeLoc3D[face][1].y / 2;
  595.     orient3DList[face][corner][1].x = orient3DList[face][corner][0].x +
  596.       (cubeLoc3D[face][2].x - subcubeLoc3D[face][2].x) / 2;
  597.     orient3DList[face][corner][1].y = orient3DList[face][corner][0].y +
  598.       (cubeLoc3D[face][2].y - subcubeLoc3D[face][2].y) / 2;
  599.     for (orient = 1; orient < MAXORIENT; orient++) {
  600.       side = corner;
  601.       MapOrientFrom3D(face, (orient + 1) % MAXORIENT, &corner);
  602.       orient3DList[face][corner][0].x =
  603.         orient3DList[face][side][0].x + diamondLoc3D[face][orient].x;
  604.       orient3DList[face][corner][0].y =
  605.         orient3DList[face][side][0].y + diamondLoc3D[face][orient].y;
  606.       orient3DList[face][corner][1].x =
  607.         orient3DList[face][side][1].x + subdiamondLoc3D[face][orient].x;
  608.       orient3DList[face][corner][1].y =
  609.         orient3DList[face][side][1].y + subdiamondLoc3D[face][orient].y;
  610.     }
  611.   }
  612. }
  613.  
  614. int SelectPolyhedrons3D(w, x, y, face, position)
  615.   Rubik3DWidget w;
  616.   int x, y;
  617.   int *face;
  618.   int *position;
  619. {
  620.   int u, v, front, tl, ur, ul, i, j;
  621.  
  622.   if (w->rubik.vertical) {
  623.     x -= w->rubik3d.viewMiddle.x;
  624.     front = (y < w->rubik3d.viewSize.y);
  625.     if (!front)
  626.       y -= (w->rubik3d.viewSize.y);
  627.     tl = (y < w->rubik3d.viewMiddle.y); 
  628.     y -= w->rubik3d.viewMiddle.y;
  629.     u = -w->rubik3d.faceSize.y * x + w->rubik3d.faceDiagonal * y;
  630.     v = w->rubik3d.faceSize.y * x + w->rubik3d.faceDiagonal * y;
  631.     ur = (u < 0);
  632.     ul = (v < 0);
  633.     if (front) {
  634.       if (tl)
  635.         *face = (ur) ? 0 : 1;
  636.       else
  637.         *face = (ul) ? 1 : 2;
  638.     } else {
  639.       if (tl)
  640.         *face = (ul) ? 4 : 3;
  641.       else
  642.         *face = (ur) ? 3 : 5;
  643.     }
  644.   } else {
  645.     y -= w->rubik3d.viewMiddle.y;
  646.     front = (x < w->rubik3d.viewSize.x);
  647.     if (!front)
  648.       x -= (w->rubik3d.viewSize.x);
  649.     tl = (x < w->rubik3d.viewMiddle.x); 
  650.     x -= w->rubik3d.viewMiddle.x;
  651.     u = -w->rubik3d.faceSize.x * y + w->rubik3d.faceDiagonal * x;
  652.     v = w->rubik3d.faceSize.x * y + w->rubik3d.faceDiagonal * x;
  653.     ur = (u < 0);
  654.     ul = (v < 0);
  655.     if (front) {
  656.       if (tl)
  657.         *face = (ur) ? 1 : 0;
  658.       else
  659.         *face = (ul) ? 0 : 2;
  660.     } else {
  661.       if (tl)
  662.         *face = (ul) ? 3 : 4;
  663.       else
  664.         *face = (ur) ? 4 : 5;
  665.     }
  666.   }
  667.   if (w->rubik.vertical)
  668.     switch (*face) {
  669.       case 0:
  670.         i = (x - 2 - (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
  671.           (w->rubik3d.cubeSize.x + w->rubik.delta);
  672.         j = (y + 2) / (w->rubik3d.cubeSize.y + w->rubik.delta) +
  673.       w->rubik.size - 1;
  674.         break;
  675.       case 1:
  676.         i = (x + 4 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y))/
  677.           (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta)) + w->rubik.size - 1;
  678.         j = (-x - 6 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y))/
  679.           (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta));
  680.         break;
  681.       case 2:
  682.         i = (x - 4 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y))/
  683.           (w->rubik3d.cubeSize.x + w->rubik.delta);
  684.         j = (y - 4) / (w->rubik3d.cubeSize.y + w->rubik.delta);
  685.         break;
  686.       case 3:
  687.         i = (-x + 5 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y))/
  688.           (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta)) + w->rubik.size - 1;
  689.         j = (-x + 7 - (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y))/
  690.           (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta)) + w->rubik.size - 1;
  691.         break;
  692.       case 4:
  693.         i = (x + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y))/
  694.           (w->rubik3d.cubeSize.x + w->rubik.delta) + w->rubik.size - 1;
  695.         j = (y - 2) / (w->rubik3d.cubeSize.y + w->rubik.delta) +
  696.       w->rubik.size - 1;
  697.         break;
  698.       case 5:
  699.         i = (x + 2 - (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y))/
  700.           (w->rubik3d.cubeSize.x + w->rubik.delta) + w->rubik.size - 1;
  701.         j = (y - 6) / (w->rubik3d.cubeSize.y + w->rubik.delta);
  702.         break;
  703.      default:
  704.         return FALSE;
  705.    }
  706.  else
  707.    switch (*face) {
  708.      case 0:
  709.        i = (-y - 3 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
  710.          (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta));
  711.        j = (y + 1 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
  712.          (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta)) + w->rubik.size - 1;
  713.        break;
  714.      case 1:
  715.        i = (x + 2) / (w->rubik3d.cubeSize.x + w->rubik.delta) +
  716.      w->rubik.size - 1;
  717.        j = (y - 3 - (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
  718.          (w->rubik3d.cubeSize.y + w->rubik.delta);
  719.        break;
  720.      case 2:
  721.        i = (x - 4) / (w->rubik3d.cubeSize.x + w->rubik.delta);
  722.        j = (y - 6 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
  723.          (w->rubik3d.cubeSize.y + w->rubik.delta);
  724.        break;
  725.      case 3:
  726.        i = x / (w->rubik3d.cubeSize.x + w->rubik.delta) +
  727.      w->rubik.size - 1;
  728.        j = (y + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
  729.          (w->rubik3d.cubeSize.y + w->rubik.delta) + w->rubik.size - 1;
  730.        break;
  731.      case 4:
  732.        i = (-y + 9 - (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x))/
  733.          (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta)) + w->rubik.size - 1;
  734.        j = (-y + 7 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x))/
  735.          (2 * (w->rubik3d.cubeDiagonal + w->rubik.delta)) + w->rubik.size - 1;
  736.        break;
  737.      case 5:
  738.        i = (-x + 7) / (w->rubik3d.cubeSize.x + w->rubik.delta) +
  739.      w->rubik.size - 1;
  740.        j = (-y - 4 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x))/
  741.          (w->rubik3d.cubeSize.y + w->rubik.delta);
  742.        break;
  743.      default:
  744.         return FALSE;
  745.     }
  746.   if (i < 0 || j < 0 || i >= w->rubik.size || j >= w->rubik.size)
  747.     return FALSE;
  748.   *position = j * w->rubik.size + i;
  749.   return TRUE;
  750. }
  751.  
  752. int NarrowSelection3D(w, face, position, direction)
  753.   Rubik3DWidget w;
  754.   int *face;
  755.   int *position;
  756.   int *direction;
  757. {
  758.   int i, j;
  759.  
  760.   switch (*direction) {
  761.     case TOP:
  762.     case RIGHT:
  763.     case BOTTOM:
  764.     case LEFT:
  765.       if (w->rubik.vertical) {
  766.     if (*face == 1 || *face == 3)
  767.           return FALSE;
  768.       } else {
  769.     if (*face == 0 || *face == 4)
  770.           return FALSE;
  771.         if (*face == 5)
  772.       *direction = (*direction + 2) % MAXORIENT;
  773.       }
  774.       break;
  775.     case CCW:
  776.     case CW:
  777.       break;
  778.     case TR:
  779.       if (w->rubik.vertical) {
  780.         if (*face == 0 || *face == 5)
  781.           return FALSE;
  782.         else if (*face == 1 || *face == 2 || *face == 4)
  783.           *direction = TOP;
  784.         else /* (*face == 3) */
  785.           *direction = LEFT;
  786.       } else {
  787.         if (*face == 1 || *face == 5)
  788.           return FALSE;
  789.         else if (*face == 0 || *face == 2 || *face == 3)
  790.           *direction = RIGHT;
  791.         else /* (*face == 4) */
  792.           *direction = BOTTOM;
  793.       }
  794.       break;
  795.     case BR:
  796.       if (w->rubik.vertical) {
  797.         if (*face == 2 || *face == 4)
  798.           return FALSE;
  799.         else if (*face == 0 || *face == 5)
  800.           *direction = BOTTOM;
  801.         else if (*face == 1)
  802.           *direction = RIGHT;
  803.         else /* (*face == 3) */
  804.           *direction = TOP;
  805.       } else {
  806.         if (*face == 2 || *face == 3)
  807.           return FALSE;
  808.         else if (*face == 4 || *face == 5)
  809.           *direction = LEFT;
  810.         else if (*face == 0)
  811.           *direction = BOTTOM;
  812.         else /* (*face == 1) */
  813.           *direction = RIGHT;
  814.       }
  815.       break;
  816.     case BL:
  817.       if (w->rubik.vertical) {
  818.         if (*face == 0 || *face == 5)
  819.           return FALSE;
  820.         else if (*face == 1 || *face == 2 || *face == 4)
  821.           *direction = BOTTOM;
  822.         else /* (*face == 3) */
  823.           *direction = RIGHT;
  824.       } else {
  825.         if (*face == 1 || *face == 5)
  826.           return FALSE;
  827.         else if (*face == 0 || *face == 2 || *face == 3)
  828.           *direction = LEFT;
  829.         else /* (*face == 4) */
  830.           *direction = TOP;
  831.       }
  832.       break;
  833.     case TL:
  834.       if (w->rubik.vertical) {
  835.         if (*face == 2 || *face == 4)
  836.           return FALSE;
  837.         else if (*face == 0 || *face == 5)
  838.           *direction = TOP;
  839.         else if (*face == 1)
  840.           *direction = LEFT;
  841.         else /* (*face == 3) */
  842.           *direction = BOTTOM;
  843.       } else {
  844.         if (*face == 2 || *face == 3)
  845.           return FALSE;
  846.         else if (*face == 4 || *face == 5)
  847.           *direction = RIGHT;
  848.         else if (*face == 0)
  849.           *direction = TOP;
  850.         else /* (*face == 1) */
  851.           *direction = LEFT;
  852.       }
  853.       break;
  854.     default:
  855.       return FALSE;
  856.   }
  857.   /*cubeDiag = (w->rubik3d.faceDiagonal + w->rubik.delta) / w->rubik.size +
  858.     w->rubik.delta;*/
  859.   /* Remap to row movement */
  860.   if (*direction == CW || *direction == CCW) {
  861.     *direction = (*direction == CCW) ?
  862.       (rotateToRow[*face].direction + 2) % MAXORIENT :
  863.       rotateToRow[*face].direction;
  864.     i = j = (rotateToRow[*face].sideFace == LEFT ||
  865.                rotateToRow[*face].sideFace == BOTTOM) ?
  866.       w->rubik.size - 1 : 0;
  867.     *face = rotateToRow[*face].face;
  868.     *position = j * w->rubik.size + i;
  869.   }
  870.   return TRUE;
  871. }
  872.  
  873. static void DrawFrame(w, gc)
  874.   Rubik3DWidget w;
  875.   GC gc;
  876. {
  877.   int face, dx, dy;
  878.  
  879.   dx = w->rubik3d.viewSize.x + w->rubik.puzzleOffset.x;
  880.   dy = w->rubik3d.viewSize.y + w->rubik.puzzleOffset.y;
  881.   if (w->rubik.vertical) {
  882.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  883.       0, dy, dx + w->rubik.puzzleOffset.x + 1, dy);
  884.     XDrawString(XtDisplay(w), XtWindow(w), gc,
  885.       (int) (2 * w->rubik.delta),
  886.       (int) (3 * w->rubik.delta + w->rubik.letterOffset.y),
  887.       "Front", 5);
  888.     XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
  889.       (-4 * w->rubik.delta + 2 * 4 * w->rubik.letterOffset.x + w->core.width), 
  890.       (int) (-w->rubik.delta - 2 * w->rubik.letterOffset.y + w->core.height),
  891.       "Back", 4);
  892.   } else {
  893.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  894.       dx, 0, dx, dy + w->rubik.puzzleOffset.y + 1);
  895.     XDrawString(XtDisplay(w), XtWindow(w), gc,
  896.       (int) (2 * w->rubik.delta),
  897.       (int) (3 * w->rubik.delta + w->rubik.letterOffset.y),
  898.       "Front", 5);
  899.     XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
  900.       (-4 * w->rubik.delta + 2 * 4 * w->rubik.letterOffset.x + w->core.width), 
  901.       (int) (-w->rubik.delta - 2 * w->rubik.letterOffset.y + w->core.height),
  902.       "Back", 4);
  903.   }
  904.   for (face = 0; face < MAXFACES; face++)
  905.     XDrawLines(XtDisplay(w), XtWindow(w), gc,
  906.       faceLoc3D[face], MAXORIENT, CoordModePrevious);
  907. }   
  908.  
  909. void DrawSquare3D(w, face, position, offset)
  910.   Rubik3DWidget w;
  911.   int face, position, offset;
  912. {
  913.   int x, y, dx, dy, i, j;
  914.  
  915.   i = position % w->rubik.size;
  916.   j = position / w->rubik.size;
  917.   MapTo3D(w, face, i, j, &x, &y);
  918.   CubeOffset3D(w, face, x, y, &dx, &dy);
  919.   cubeLoc3D[face][0].x = dx;
  920.   cubeLoc3D[face][0].y = dy;
  921.   if (offset) {
  922.     XFillPolygon(XtDisplay(w), XtWindow(w),
  923.       w->rubik.borderGC,
  924.       cubeLoc3D[face], MAXORIENT, Convex, CoordModePrevious);
  925.     XDrawLines(XtDisplay(w), XtWindow(w),
  926.       w->rubik.faceGC[w->rubik.cubeLoc[face][position].face],
  927.       cubeLoc3D[face], 5, CoordModePrevious);
  928.   } else {
  929.     XFillPolygon(XtDisplay(w), XtWindow(w),
  930.       w->rubik.faceGC[w->rubik.cubeLoc[face][position].face],
  931.       cubeLoc3D[face], MAXORIENT, Convex, CoordModePrevious);
  932.     XDrawLines(XtDisplay(w), XtWindow(w),
  933.       w->rubik.borderGC, cubeLoc3D[face], 5, CoordModePrevious);
  934.   }
  935.   if (w->rubik.depth == 1 || w->rubik.mono) {
  936.     int letterX, letterY;
  937.     char buf[2];
  938.  
  939.     (void) sprintf (buf, "%c",
  940.              w->rubik.faceName[w->rubik.cubeLoc[face][position].face][0]);
  941.     letterX = dx + letter3DList[face].x + w->rubik.letterOffset.x;
  942.     letterY = dy + letter3DList[face].y + w->rubik.letterOffset.y;
  943.     XDrawString(XtDisplay(w), XtWindow(w), w->rubik.inverseGC,
  944.       letterX, letterY, buf, 1);
  945.   }
  946.   if (w->rubik.orient)
  947.     XDrawLine(XtDisplay(w), XtWindow(w), w->rubik.inverseGC,
  948.       dx + orient3DList[face][w->rubik.cubeLoc[face][position].rotation][0].x,
  949.       dy + orient3DList[face][w->rubik.cubeLoc[face][position].rotation][0].y,
  950.       dx + orient3DList[face][w->rubik.cubeLoc[face][position].rotation][1].x,
  951.       dy + orient3DList[face][w->rubik.cubeLoc[face][position].rotation][1].y);
  952. }
  953.  
  954. static void MapTo3D(w, face, i, j, x, y)
  955.   Rubik3DWidget w;
  956.   int face, i, j, *x, *y;
  957. {
  958.   switch (face) {
  959.     case 0:
  960.       *x = w->rubik.size - 1 - j;
  961.       *y = i;
  962.       break;
  963.     case 1:
  964.       *x = j;
  965.       *y = w->rubik.size - 1 - i;
  966.       break;
  967.     case 2:
  968.       *x = i;
  969.       *y = j;
  970.       break;
  971.     case 3:
  972.       *x = w->rubik.size - 1 - i;
  973.       *y = w->rubik.size - 1 - j;
  974.       break;
  975.     case 4:
  976.       *x = w->rubik.size - 1 - i;
  977.       *y = w->rubik.size - 1 - j;
  978.       break;
  979.     case 5:
  980.       *x = j;
  981.       *y = w->rubik.size - 1 - i;
  982.       break;
  983.     default:
  984.       (void) printf ("MapTo3D: face %d\n", face);
  985.   }
  986. }
  987.  
  988. #ifdef DEBUG
  989. static void MapFrom3D(w, face, x, y, i, j)
  990.   Rubik3DWidget w;
  991.   int face, x, y, *i, *j;
  992. {
  993.   switch (face) {
  994.     case 0:
  995.       *i = y;
  996.       *j = w->rubik.size - 1 - x;
  997.       break;
  998.     case 1:
  999.       *i = w->rubik.size - 1 - y;
  1000.       *j = x;
  1001.       break;
  1002.     case 2:
  1003.       *i = x;
  1004.       *j = y;
  1005.       break;
  1006.     case 3:
  1007.       *i = w->rubik.size - 1 - x;
  1008.       *j = w->rubik.size - 1 - y;
  1009.       break;
  1010.     case 4:
  1011.       *i = w->rubik.size - 1 - x;
  1012.       *j = w->rubik.size - 1 - y;
  1013.       break;
  1014.     case 5:
  1015.       *i = w->rubik.size - 1 - y;
  1016.       *j = x;
  1017.       break;
  1018.     default:
  1019.       (void) printf ("MapFrom3D: face %d\n", face);
  1020.   }
  1021. }
  1022. #endif
  1023.  
  1024. static void MapOrientFrom3D(face, corner, side)
  1025.   int face, corner, *side;
  1026. {
  1027.   switch (face) {
  1028.     case 0:
  1029.       *side = (corner + 2) % MAXORIENT;
  1030.       break;
  1031.     case 1:
  1032.       *side = corner;
  1033.       break;
  1034.     case 2:
  1035.       *side = (corner + 3) % MAXORIENT;
  1036.       break;
  1037.     case 3:
  1038.       *side = (corner + 1) % MAXORIENT;
  1039.       break;
  1040.     case 4:
  1041.       *side = (corner + 1) % MAXORIENT;
  1042.       break;
  1043.     case 5:
  1044.       *side = corner;
  1045.       break;
  1046.     default:
  1047.       (void) printf ("MapFrom3D: face %d\n", face);
  1048.   }
  1049. }
  1050.  
  1051. static void CubeOffset3D(w, face, x, y, dx, dy)
  1052.   Rubik3DWidget w;
  1053.   int face, x, y, *dx, *dy;
  1054. {
  1055.   if (w->rubik.vertical)
  1056.     switch (face) {
  1057.       case 0:
  1058.         *dx = w->rubik3d.viewMiddle.x + w->rubik.delta - 1 +
  1059.           y * (w->rubik3d.cubeSize.x + w->rubik.delta) -
  1060.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1061.         *dy = w->rubik3d.viewMiddle.y - w->rubik.delta - 2 -
  1062.           x * (w->rubik3d.cubeSize.y + w->rubik.delta);
  1063.         break;
  1064.       case 1:
  1065.         *dx = w->rubik3d.viewMiddle.x - 2 * w->rubik.delta -
  1066.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta) -
  1067.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1068.         *dy = w->rubik3d.viewMiddle.y +
  1069.           x * (w->rubik3d.cubeSize.y + w->rubik.delta) -
  1070.           y * (w->rubik3d.cubeSize.y + w->rubik.delta);
  1071.         break;
  1072.       case 2:
  1073.         *dx = w->rubik3d.viewMiddle.x + w->rubik.delta - 1 +
  1074.           x * (w->rubik3d.cubeSize.x + w->rubik.delta) -
  1075.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1076.         *dy = w->rubik3d.viewMiddle.y + 2 * w->rubik.delta - 1 +
  1077.           y * (w->rubik3d.cubeSize.y + w->rubik.delta);
  1078.         break;
  1079.       case 3:
  1080.         *dx = w->rubik3d.viewMiddle.x + 2 * w->rubik.delta +
  1081.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta) +
  1082.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1083.         *dy = w->rubik3d.viewSize.y + w->rubik3d.viewMiddle.y + 
  1084.               w->rubik.delta - 1 -
  1085.           x * (w->rubik3d.cubeSize.y + w->rubik.delta) +
  1086.           y * (w->rubik3d.cubeSize.y + w->rubik.delta);
  1087.         break;
  1088.       case 4:
  1089.         *dx = w->rubik3d.viewMiddle.x - w->rubik.delta + 1 -
  1090.           x * (w->rubik3d.cubeSize.x + w->rubik.delta) +
  1091.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1092.         *dy = w->rubik3d.viewSize.y + w->rubik3d.viewMiddle.y -
  1093.               w->rubik.delta + 1 -
  1094.           y * (w->rubik3d.cubeSize.y + w->rubik.delta);
  1095.         break;
  1096.       case 5:
  1097.         *dx = w->rubik3d.viewMiddle.x - 2 -
  1098.           y * (w->rubik3d.cubeSize.x + w->rubik.delta) +
  1099.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1100.         *dy = w->rubik3d.viewSize.y + w->rubik3d.viewMiddle.y +
  1101.               2 * w->rubik.delta + 2 +
  1102.           x * (w->rubik3d.cubeSize.y + w->rubik.delta);
  1103.         break;
  1104.       default:
  1105.         (void) printf ("CubeOffset3D: face %d\n", face);
  1106.     } else switch (face) {
  1107.       case 0:
  1108.         *dx = w->rubik3d.viewMiddle.x +
  1109.           y * (w->rubik3d.cubeSize.x + w->rubik.delta) -
  1110.           x * (w->rubik3d.cubeSize.x + w->rubik.delta);
  1111.         *dy = w->rubik3d.viewMiddle.y - 2 * w->rubik.delta + 1 -
  1112.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta) -
  1113.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1114.         break;
  1115.       case 1:
  1116.         *dx = w->rubik3d.viewMiddle.x - w->rubik.delta - 2 -
  1117.           y * (w->rubik3d.cubeSize.x + w->rubik.delta);
  1118.         *dy = w->rubik3d.viewMiddle.y + w->rubik.delta +
  1119.           x * (w->rubik3d.cubeSize.y + w->rubik.delta) -
  1120.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1121.         break;
  1122.       case 2:
  1123.         *dx = w->rubik3d.viewMiddle.x + 2 * w->rubik.delta - 1 +
  1124.           x * (w->rubik3d.cubeSize.x + w->rubik.delta);
  1125.         *dy = w->rubik3d.viewMiddle.y + w->rubik.delta +
  1126.           y * (w->rubik3d.cubeSize.y + w->rubik.delta) -
  1127.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta); 
  1128.         break;
  1129.       case 3:
  1130.         *dx = w->rubik3d.viewSize.x + w->rubik3d.viewMiddle.x -
  1131.               w->rubik.delta + 1 -
  1132.           x * (w->rubik3d.cubeSize.x + w->rubik.delta);
  1133.         *dy = w->rubik3d.viewMiddle.y - w->rubik.delta -
  1134.           y * (w->rubik3d.cubeSize.y + w->rubik.delta) +
  1135.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1136.         break;
  1137.       case 4:
  1138.         *dx = w->rubik3d.viewSize.x + w->rubik3d.viewMiddle.x +
  1139.               w->rubik.delta - 1 -
  1140.           y * (w->rubik3d.cubeSize.x + w->rubik.delta) +
  1141.           x * (w->rubik3d.cubeSize.x + w->rubik.delta);
  1142.         *dy = w->rubik3d.viewMiddle.y + 2 * w->rubik.delta +
  1143.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta) +
  1144.           x * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1145.         break;
  1146.       case 5:
  1147.         *dx = w->rubik3d.viewSize.x + w->rubik3d.viewMiddle.x +
  1148.               2 * w->rubik.delta + 2 +
  1149.           y * (w->rubik3d.cubeSize.x + w->rubik.delta);
  1150.         *dy = w->rubik3d.viewMiddle.y - w->rubik.delta -
  1151.           x * (w->rubik3d.cubeSize.y + w->rubik.delta) +
  1152.           y * (w->rubik3d.cubeDiagonal + w->rubik.delta);
  1153.         break;
  1154.       default:
  1155.         (void) printf ("CubeOffset3D: face %d\n", face);
  1156.     }
  1157. }
  1158.